package com.xq.myxmpp;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.ReconnectionManager;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatManagerListener;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.filter.FlexibleStanzaTypeFilter;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.OrFilter;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.filter.StanzaTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.roster.RosterGroup;
import org.jivesoftware.smack.roster.RosterLoadedListener;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.chatstates.ChatState;
import org.jivesoftware.smackx.chatstates.packet.ChatStateExtension;
import org.jivesoftware.smackx.iqregister.AccountManager;
import org.jivesoftware.smackx.muc.Affiliate;
import org.jivesoftware.smackx.muc.DiscussionHistory;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jivesoftware.smackx.muc.packet.MUCInitialPresence;
import org.jivesoftware.smackx.receipts.DeliveryReceiptManager;
import org.jivesoftware.smackx.receipts.ReceiptReceivedListener;
import org.jivesoftware.smackx.xdata.Form;
import org.jivesoftware.smackx.xdata.FormField;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.DomainFullJid;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityFullJid;
import org.jxmpp.jid.EntityJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Localpart;
import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;

import javax.net.ssl.HostnameVerifier;

@SuppressWarnings("deprecation")
public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    String account = "xq234";
    String password = "xq234";
    final String xmppDomain = "192.168.0.134";
    private final String roomName = "111111";
    private final String resource = "android";
    final String roomJid = roomName + "@conference." + xmppDomain;//房间标识

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.i(TAG, "onCreate: ========================");
    }


    private XMPPTCPConnection connection;

    /**
     * 获得与服务器的连接
     */
    public void getConnection() {
        final int port = 5222;
        final String jid = account + "@" + xmppDomain;//

        if (connection != null && connection.isAuthenticated()) {
            // avoid duplicate login
            Log.i(TAG, "getConnection: avoid duplicate login ");
            return;
        }

        final String[] jidParts = jid.split("@");
        String[] serviceNameParts = jidParts[1].split("/");
        String serviceName = serviceNameParts[0];
        DomainBareJid serverName = null;

        try {
            Log.i(TAG, "getConnection: serviceName  == " + serviceName);

            //房间
            String roomJidString = roomName + "@conference." + xmppDomain;
            //111111@conference.192.168.0.134

            //房间内用户
            String userInRoomJidString = roomName + "@conference." + xmppDomain + "/" + account;
            //111111@conference.192.168.0.134/xq234

            //服务器用户
            String userJidString = account + "@" + xmppDomain + "/" + resource;
            //xq234@192.168.0.134/android

            String jidString = userInRoomJidString;

            //  `@`[结果]`/`
            DomainBareJid domainBareJid = JidCreate.domainBareFrom(jidString);
            Log.i(TAG, "getConnection: domainBareJid  == " + domainBareJid);
            //conference.192.168.0.134
            //192.168.0.134

            //  `@`[结果]
            DomainFullJid domainFullJid = JidCreate.domainFullFrom(jidString);
            Log.i(TAG, "getConnection: domainFullJid  == " + domainFullJid);
            //conference.192.168.0.134/xq234
            //192.168.0.134/android

            //  [结果]`/`
            EntityBareJid entityBareJid = JidCreate.entityBareFrom(jidString);
            Log.i(TAG, "getConnection: entityBareJid  == " + entityBareJid);
            //111111@conference.192.168.0.134
            //xq234@192.168.0.134

            //  全地址
            EntityFullJid entityFullJid = JidCreate.entityFullFrom(jidString);
            Log.i(TAG, "getConnection: entityFullJid  == " + entityFullJid);
            //111111@conference.192.168.0.134/xq234
            //xq234@192.168.0.134/android

            serverName = JidCreate.domainBareFrom(serviceName);
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "getConnection: e === " + e.getMessage());
        }

        XMPPTCPConnectionConfiguration.Builder confBuilder = null;
        try {
            InetAddress inetAddress = getInetAddressByName(xmppDomain);
            HostnameVerifier verifier = (hostname, session) -> true;

            Log.i(TAG, "connect: account = " + jidParts[0]);
            Log.i(TAG, "connect: password = " + password);
            Log.i(TAG, "connect: serverName = " + serverName);
            Log.i(TAG, "connect: verifier = " + verifier);
            Log.i(TAG, "connect: inetAddress = " + inetAddress);
            confBuilder = XMPPTCPConnectionConfiguration.builder()
                    //设置 XMPP 实体的用户名和密码。
                    //用户名通常是客户端 JID 的本地部分。
                    // 但是一些 SASL 机制或服务可能需要不同的格式（例如完整的 JID）作为使用的授权标识
                    .setUsernameAndPassword(jidParts[0], password)
                    //设置 XMPP 域。 XMPP 域是 XMPP 地址 (JID) 中“@”符号之后的内容。
                    .setXmppDomain(serverName)
                    .setConnectTimeout(30000)
                    //设置用于验证使用此 ConnectionConfiguration
                    // 创建的 XMPP 连接所使用的 SSLSocket 的主机名的 HostnameVerifier
                    .setHostnameVerifier(verifier)
                    //设置提供 XMPP 服务的主机的 Internet 地址。
                    // 如果设置，那么这将覆盖通过setHost(String)设置的任何内容。
                    .setHostAddress(inetAddress)
                    //设置是否将初始可用状态发送到服务器。
                    // 默认情况下，可用状态将发送到服务器，指示此状态不在线且可用于接收消息。
                    // 如果您想在不被“注意”的情况下登录，则传递一个假值。
                    .setSendPresence(true)
                    .setPort(port)
                    //将给定的机制添加到启用的机制中。
                    // 有关启用的 SASL 机制的讨论，请参阅addEnabledSaslMechanism(Collection) 。
                    .addEnabledSaslMechanism(SASLMechanism.PLAIN)
                    //是否开启安全模式
                    .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);

//            if (serviceNameParts.length > 1) {
//                confBuilder.setResource(serviceNameParts[1]);
//            } else {
//                confBuilder.setResource(Long.toHexString(Double.doubleToLongBits(Math.random())));
//            }
            //设置我们从服务器请求的资源。
            confBuilder.setResource("android");
        } catch (XmppStringprepException e) {
            e.printStackTrace();
        }

//        if (trustedHosts.contains(hostname) || (hostname == null && trustedHosts.contains(serviceName))) {
//            confBuilder.setSecurityMode(SecurityMode.disabled);
//            TLSUtils.disableHostnameVerificationForTlsCertificates(confBuilder);
//
//            try {
//                TLSUtils.acceptAllCertificates(confBuilder);
//            } catch (NoSuchAlgorithmException | KeyManagementException e) {
//                e.printStackTrace();
//            }
//        }


        XMPPTCPConnectionConfiguration connectionConfiguration = confBuilder.build();
        try {
            connection = new XMPPTCPConnection(connectionConfiguration);
        } catch (Exception e) {
            e.printStackTrace();
        }

        connection.setReplyTimeout(30000);
        connection.setUseStreamManagement(true);
        connection.addAsyncStanzaListener(
                //提供一种机制来侦听通过指定过滤器的数据包。
                stanzaListener,
                //定义一种过滤特定属性的节的方法
                new OrFilter(new StanzaTypeFilter(IQ.class), new StanzaTypeFilter(Presence.class)));
        connection.addConnectionListener(connectionListener);

        DeliveryReceiptManager receiptManager = DeliveryReceiptManager.getInstanceFor(connection);
        //使用ReceiptReceivedListener了解传入的交货收据。
        receiptManager.addReceiptReceivedListener(receiptReceivedListener);
        receiptManager.autoAddDeliveryReceiptRequests();

        ChatManager chatManager = ChatManager.getInstanceFor(connection);
        //向 ChatManager 注册一个新的侦听器以接收与聊天相关的事件。
        chatManager.addChatListener(chatManagerListener);


        StanzaFilter packetFilter = new OrFilter(MessageTypeFilter.CHAT, new FlexibleStanzaTypeFilter<Message>() {

            @Override
            protected boolean acceptSpecific(Message message) {
                return (message.getType() == Message.Type.normal);
            }

        });

        connection.addSyncStanzaListener(packet -> {
            Message message = (Message) packet;
            Log.i(TAG, "addSyncStanzaListener processStanza: " + message.toString());
            Jid from = message.getFrom();
            // According to RFC6120 8.1.2.1 4. messages without a 'from' attribute are valid, but they
            // are of no use in this case for ChatManager
            if (from == null) {
                return;
            }

            EntityJid userJID = from.asEntityJidIfPossible();
            if (userJID == null) {
                message.setFrom("notify@" + from.toString());
                Log.i("XMPP", "Notify message without localpart: '" + message.toXML(null) + "'");
            }
        }, packetFilter);

        Roster roster = Roster.getInstanceFor(connection);
        //添加名册加载的侦听器。
        roster.addRosterLoadedListener(new RosterLoadedListener() {

            @Override
            public void onRosterLoaded(Roster roster) {
                Log.i(TAG, "RosterLoadedListener onRosterLoaded: ");

            }

            @Override
            public void onRosterLoadingFailed(Exception exception) {
                Log.i(TAG, "RosterLoadedListener onRosterLoadingFailed: ");

            }
        });
        new Thread(() -> {
            try {
                ReconnectionManager manager = ReconnectionManager.getInstanceFor(connection);
                manager.setFixedDelay(5);
                manager.enableAutomaticReconnection();
                ReconnectionManager.setEnabledPerDefault(true);
                connection.connect().login();
            } catch (Exception e) {
                e.printStackTrace();
                Log.i(TAG, "run: Could not login for current user", e);
            }
        }).start();
    }

    public void disconnect() {
        connection.disconnect();
    }

    public static InetAddress getInetAddressByName(String name) {
        AsyncTask<String, Void, InetAddress> task = new AsyncTask<String, Void, InetAddress>() {

            @Override
            protected InetAddress doInBackground(String... params) {
                try {
                    return InetAddress.getByName(params[0]);
                } catch (UnknownHostException e) {
                    return null;
                }
            }
        };

        try {
            return task.execute(name).get();
        } catch (InterruptedException | ExecutionException e) {
            return null;
        }

    }

    private final ChatManagerListener chatManagerListener =
            (chat, createdLocally) -> {
                Log.i(TAG, "chatManagerListener chatCreated: ");
                Log.i(TAG, "chatManagerListener chatCreated: createdLocally = " + createdLocally);
                chat.addMessageListener(new ChatMessageListener() {
                    @Override
                    public void processMessage(Chat chat, Message message) {
                        Log.w(TAG, "ChatManagerListener processStanza: Message getFrom===================" + message.getFrom().toString());
                        Log.w(TAG, "ChatManagerListener processStanza: Message getStanzaId===================" + message.getStanzaId());
                        Log.w(TAG, "ChatManagerListener processStanza: Message getBody===================" + message.getBody());
                        Log.w(TAG, "ChatManagerListener processStanza: Message getType===================" + message.getType());
                        Log.w(TAG, "ChatManagerListener processStanza: Message getThread===================" + message.getThread());
                        Log.w(TAG, "ChatManagerListener processStanza: Message getSubject===================" + message.getSubject());
                        Log.w(TAG, "ChatManagerListener processStanza: Message src===================" + message.toXML("").toString());
                    }
                });
            };

    private final ReceiptReceivedListener receiptReceivedListener =
            (fromJid, toJid, receiptId, receipt) -> {
                Log.i(TAG, "receiptReceivedListener onReceiptReceived: fromJid = " + fromJid);
                Log.i(TAG, "receiptReceivedListener onReceiptReceived: toJid = " + toJid);
                Log.i(TAG, "receiptReceivedListener onReceiptReceived: receiptId = " + receiptId);
                Log.i(TAG, "receiptReceivedListener onReceiptReceived: receipt = " + receipt);

            };

    private final ConnectionListener connectionListener = new ConnectionListener() {
        @Override
        public void connected(XMPPConnection connection) {
            Log.i(TAG, "connectionListener connected: ");
        }

        @Override
        public void authenticated(XMPPConnection connection, boolean resumed) {
            Log.i(TAG, "connectionListener authenticated: resumed =  " + resumed);

        }

        @Override
        public void connectionClosed() {
            Log.i(TAG, "connectionListener connectionClosed: ");

        }

        @Override
        public void connectionClosedOnError(Exception e) {
            Log.i(TAG, "connectionListener connectionClosedOnError: ");

        }
    };

    private final StanzaListener stanzaListener = new StanzaListener() {
        @Override
        public void processStanza(Stanza packet)
                throws SmackException.NotConnectedException,
                InterruptedException, SmackException.NotLoggedInException {

            printStanza("stanzaListener", packet);
        }
    };

    private void printStanza(String tag, Stanza packet) {
        if (packet instanceof IQ) {
            IQ iq = (IQ) packet;
            Log.w(TAG, tag + ": IQ getType===================" + iq.getType());
            Log.w(TAG, tag + ": IQ isRequestIQ===================" + iq.isRequestIQ());
        } else if (packet instanceof Presence) {
            Presence presence = (Presence) packet;
            Log.w(TAG, tag + ":Presence getStatus===================" + presence.getStatus());
            Log.w(TAG, tag + ":Presence getType===================" + presence.getType());
            Log.w(TAG, tag + ":Presence getMode===================" + presence.getMode());
            Log.w(TAG, tag + ":Presence getPriority===================" + presence.getPriority());
            Log.w(TAG, tag + ":Presence isAway===================" + presence.isAway());
            Log.w(TAG, tag + ":Presence isAvailable===================" + presence.isAvailable());
        } else if (packet instanceof Message) {
            Message message = (Message) packet;
            Log.w(TAG, tag + ":Message getBody===================" + message.getBody());
            Log.w(TAG, tag + ":Message getType===================" + message.getType());
            Log.w(TAG, tag + ":Message getThread===================" + message.getThread());
            Log.w(TAG, tag + ":Message getSubject===================" + message.getSubject());
        } else {
            Log.w(TAG, tag + ":其他===================");
        }

        Log.w(TAG, tag + ":packet = " + packet.toXML("").toString());
    }


    /**
     * 创建一个新用户
     *
     * @param username 用户名
     * @param password 密码
     * @param attr     一些用户资料
     * @see AccountManager
     */
    public boolean registerAccount(String username, String password, Map<String, String> attr) {
        AccountManager manager = AccountManager.getInstance(connection);
        try {
            if (attr == null) {
                manager.createAccount(Localpart.fromOrThrowUnchecked(username), password);
            } else {
                manager.createAccount(Localpart.fromOrThrowUnchecked(username), password, attr);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 登录
     *
     * @param userName 用户名
     * @param password 密码
     */
    public void login(final String userName, final String password) {
        new Thread(() -> {
            try {
                connection.login(userName, password);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    /**
     * 退出登录
     */
    public void logout() {
        try {
            connection.instantShutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 修改密码
     *
     * @param newPassword 　新密码
     * @return code
     * @code true 修改成功
     * @code false 修改失败
     */
    public boolean changePassword(String newPassword) {
        try {
            AccountManager manager = AccountManager.getInstance(connection);
            manager.changePassword(newPassword);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    private void configRoom(MultiUserChat muc, String roomName) {
        try {
            List<Affiliate> owners = muc.getOwners();
            if (owners != null && owners.size() > 0) {
                for (int i = 0; i < owners.size(); i++) {
                    Affiliate affiliate = owners.get(i);
                    //    moderator,
                    //    none,
                    //    participant,
                    //    visitor;
                    Log.i(TAG, "configRoom: owner getRole = " + affiliate.getRole());
                    Log.i(TAG, "configRoom: owner getNick = " + affiliate.getNick());
                    Log.i(TAG, "configRoom: owner getJid = " + affiliate.getJid());
                    Log.i(TAG, "configRoom: owner getAffiliation = " + affiliate.getAffiliation());
                }
            } else {
                Log.i(TAG, "configRoom: owner = null");
            }

            List<Affiliate> admins = muc.getAdmins();
            if (admins != null && admins.size() > 0) {
                for (int i = 0; i < admins.size(); i++) {
                    Affiliate affiliate = admins.get(i);
                    Log.i(TAG, "configRoom: members getRole = " + affiliate.getRole());
                    Log.i(TAG, "configRoom: members getNick = " + affiliate.getNick());
                    Log.i(TAG, "configRoom: members getJid = " + affiliate.getJid());
                    Log.i(TAG, "configRoom: members getAffiliation = " + affiliate.getAffiliation());
                }
            } else {
                Log.i(TAG, "configRoom: admins = null");
            }

            //需要最高权限：房间拥有者
            List<Affiliate> members = muc.getMembers();
            if (members != null && members.size() > 0) {
                for (int i = 0; i < members.size(); i++) {
                    Affiliate affiliate = members.get(i);
                    Log.i(TAG, "configRoom: members getRole = " + affiliate.getRole());
                    Log.i(TAG, "configRoom: members getNick = " + affiliate.getNick());
                    Log.i(TAG, "configRoom: members getJid = " + affiliate.getJid());
                    Log.i(TAG, "configRoom: members getAffiliation = " + affiliate.getAffiliation());
                }
            } else {
                Log.i(TAG, "configRoom: members = null");
            }


            // 创建聊天室
            // 获得聊天室的配置表单
            Form form = muc.getConfigurationForm();
            // 根据原始表单创建一个要提交的新表单。
            Form submitForm = form.createAnswerForm();
            // 向要提交的表单添加默认答复

            List<FormField> fields = form.getFields();
            for (FormField field : fields) {
                if (!FormField.Type.hidden.equals(field.getType()) && field.getVariable() != null) {
                    submitForm.setDefaultAnswer(field.getVariable());
                    //获取配置表
                    Log.i(TAG, "configRoom 配置 : \n"
                            + field.getVariable() + "     "
                            + field.getType().toString() + "   "
                            + field.getLabel());
                }
            }

            //【拥有者】才能修改房间配置
            submitForm.setAnswer("muc#roomconfig_roomname", roomName);
            submitForm.setAnswer("muc#roomconfig_roomdesc", roomName);

            // 设置聊天室是持久聊天室，即将要被保存下来
            submitForm.setAnswer("muc#roomconfig_persistentroom", true);
//            // 房间仅对成员开放
//            submitForm.setAnswer("muc#roomconfig_membersonly", false);
//            // 允许占有者邀请其他人
//            submitForm.setAnswer("muc#roomconfig_allowinvites", true);
//            // 能够发现占有者真实 JID 的角色
//            // submitForm.setAnswer("muc#roomconfig_whois", "anyone");
//            // 登录房间对话
//            submitForm.setAnswer("muc#roomconfig_enablelogging", true);
//            // 仅允许注册的昵称登录
//            submitForm.setAnswer("x-muc#roomconfig_reservednick", true);
//            // 允许使用者修改昵称
//            submitForm.setAnswer("x-muc#roomconfig_canchangenick", false);
//            // 允许用户注册房间
//            submitForm.setAnswer("x-muc#roomconfig_registration", false);
            // 发送已完成的表单（有默认值）到服务器来配置聊天室
            muc.sendConfigurationForm(submitForm);
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "configRoom: e == " + e.getMessage());
        }
    }

    public void joinRoom(String roomJid, String roomName, String userNickname, String lastMessage) {
        try {
            MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
            MultiUserChat muc = manager.getMultiUserChat(JidCreate.entityBareFrom(roomJid));

            Log.i(TAG, "joinRoom: last message: " + lastMessage);
            DiscussionHistory history = new DiscussionHistory();
            Calendar calendar = Calendar.getInstance();
            long val = Long.parseLong(lastMessage);
            calendar.setTimeInMillis(val);
            calendar.add(Calendar.SECOND, 1);
            history.setSince(calendar.getTime());
            Log.i(TAG, "joinRoom:  Date is" + calendar.getTime());
            history.setMaxStanzas(-1);
            history.setMaxChars(-1);
            history.setSince(new Date());

            if (muc.isJoined()) {
                sendOnlinePresence(muc, roomJid, userNickname, calendar.getTime());
            } else {
                muc.join(Resourcepart.fromOrNull(userNickname), "", history, connection.getReplyTimeout());
                //添加一个节侦听器，它将在群聊中收到任何新消息的通知。
                // 只有发往该群聊的“群聊”消息才会发送给收听者。
                // 如果您希望侦听可能与此群聊相关联的其他数据包，
                // 您应该使用适当的 PacketListener 直接向 XMPPConnection 注册一个 PacketListener。
                muc.addMessageListener(messageListener);
            }
            if (!TextUtils.isEmpty(roomName)) {
                Log.i(TAG, "joinRoom: roomName 不为空 = " + roomName);
                configRoom(muc, roomName);
            } else {
                Log.i(TAG, "joinRoom: roomName 为空");
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(TAG, "joinRoom: Could not join chat room", e);
        }
    }

    private final MessageListener messageListener = message -> {
        Log.i(TAG, "processMessage: =  " + message.toString());

        HashMap<String, String> params = new HashMap<>();
        params.put("_id", message.getStanzaId());
        params.put("thread", message.getThread());
        params.put("subject", message.getSubject());
        params.put("from", message.getFrom().toString());
        params.put("src", message.toXML("").toString());
        if (message.getBody() != null) {
            params.put("body", message.getBody());
        } else {
            boolean isChatState = message.hasExtension(ChatStateExtension.NAMESPACE);
            if (isChatState) {
                ChatStateExtension extension = (ChatStateExtension) message.getExtension(ChatStateExtension.NAMESPACE);
                ChatState state = extension.getChatState();
                HashMap<String, String> paramStatus = new HashMap<>();
                paramStatus.put("from", message.getFrom().toString());
                paramStatus.put("status", state.name());
                Log.i(TAG, "processMessage: paramStatus = " + paramStatus);
            }
        }
        Log.i(TAG, "processMessage: params = " + params);

        printStanza("MessageListener", message);
    };

    private void sendOnlinePresence(MultiUserChat muc, String room, String nickname, Date date) {
        Presence joinPresence = new Presence(Presence.Type.available);
        joinPresence.setTo(room + "/" + nickname);
        MUCInitialPresence mucInitialPresence = new MUCInitialPresence();
        MUCInitialPresence.History history = new MUCInitialPresence.History();
        history.setSince(date);
        history.setMaxStanzas(-1);
        history.setMaxChars(-1);
        mucInitialPresence.setHistory(history);
        joinPresence.addExtension(mucInitialPresence);
        try {
            connection.sendStanza(joinPresence);
        } catch (Exception e) {
            Log.e(TAG, "sendOnlinePresence: e === " + e.getMessage());
        }
    }

    public void sendRoomMessage(String roomJid, String text) {
        MultiUserChatManager mucManager = MultiUserChatManager.getInstanceFor(connection);

        try {
            MultiUserChat muc = mucManager.getMultiUserChat(JidCreate.entityBareFrom(roomJid));
            muc.sendMessage(text);
        } catch (SmackException | InterruptedException | XmppStringprepException e) {
            e.printStackTrace();
            Log.e(TAG, "sendRoomMessage: e === " + e.getMessage());
        }
    }

    public void sendRoomMessageUpdated(String roomJid, String text, final String messageId) {
        MultiUserChatManager mucManager = MultiUserChatManager.getInstanceFor(connection);

        try {
            MultiUserChat muc = mucManager.getMultiUserChat(JidCreate.entityBareFrom(roomJid));
            Message message = muc.createMessage();
            message.setBody(text);
            message.setStanzaId(messageId);

            muc.sendMessage(message);
            //为给定的 ID 添加一个新的 Stanza ID 确认侦听器。
            //如果服务器确认了具有给定 ID 的节，则将调用侦听器。 侦听器运行后，它将自动删除。
            connection.addStanzaIdAcknowledgedListener(messageId, packet -> {
                Log.i(TAG, "sendRoomMessageUpdated processStanza: =================");
                Log.i(TAG, "sendRoomMessageUpdated processStanza: packet=================" + packet);
            });
        } catch (SmackException | InterruptedException | XmppStringprepException e) {
            e.printStackTrace();
            Log.e(TAG, "sendRoomMessageUpdated: e ==== " + e.getMessage());
        }
    }


    private ChatMessageListener chatMessageListener = new ChatMessageListener() {
        @Override
        public void processMessage(Chat chat, Message message) {
            printStanza("ChatMessageListener", message);
        }
    };

    public void sendMessage(String text, String to, String thread) {
        String chatIdentifier = (thread == null ? to : thread);

        ChatManager chatManager = ChatManager.getInstanceFor(connection);
        Chat chat = chatManager.getThreadChat(chatIdentifier);

        try {
            if (chat == null) {
                if (thread == null) {
                    chat = chatManager.createChat(JidCreate.entityBareFrom(to), chatMessageListener);
                } else {
                    chat = chatManager.createChat(JidCreate.entityBareFrom(to), thread, chatMessageListener);
                }
            }

            Message message = new Message();
            message.setBody(text);
            message.setFrom(connection.getUser());

            chat.sendMessage(message);
            message.setBody(text);
            message.setFrom(connection.getUser());

            connection.addStanzaIdAcknowledgedListener(message.getStanzaId(), new StanzaListener() {
                @Override
                public void processStanza(Stanza packet) {
                    printStanza("ChatMessageListener", packet);
                }
            });

        } catch (SmackException | InterruptedException | XmppStringprepException e) {
            e.printStackTrace();
        }
    }

    public void sendMessageUpdated(String text, String to, String thread, final String messageId) {
        String chatIdentifier = (thread == null ? to : thread);

        ChatManager chatManager = ChatManager.getInstanceFor(connection);
        Chat chat = chatManager.getThreadChat(chatIdentifier);

        try {
            if (chat == null) {
                if (thread == null) {
                    chat = chatManager.createChat(JidCreate.entityBareFrom(to), chatMessageListener);
                } else {
                    chat = chatManager.createChat(JidCreate.entityBareFrom(to), thread, chatMessageListener);
                }
            }

            Message message = new Message();
            message.setStanzaId(messageId);
            message.setBody(text);
            message.setFrom(connection.getUser());

            chat.sendMessage(message);
            connection.addStanzaIdAcknowledgedListener(messageId, new StanzaListener() {
                @Override
                public void processStanza(Stanza packet) throws SmackException.NotConnectedException {
                    printStanza("addStanzaIdAcknowledgedListener", packet);
                }
            });

        } catch (SmackException | InterruptedException | XmppStringprepException e) {
            e.printStackTrace();
        }
    }

    private String generateMessageId() {
        Message message = new Message();
        return message.getStanzaId();
    }

    public void presence(String to, String type) {
        try {
            connection.sendStanza(new Presence(Presence.Type.fromString(type), type, 1, Presence.Mode.available));
        } catch (SmackException.NotConnectedException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void removeRoster(String to) {
        Roster roster = Roster.getInstanceFor(connection);
        RosterEntry rosterEntry = null;
        try {
            rosterEntry = roster.getEntry(JidCreate.entityBareFrom(to));
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (rosterEntry != null) {
            try {
                roster.removeEntry(rosterEntry);
            } catch (SmackException.NotLoggedInException | SmackException.NotConnectedException | XMPPException.XMPPErrorException | SmackException.NoResponseException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void createRoasterEntry(String jabberId, String name) {
        Roster roster = Roster.getInstanceFor(connection);
        RosterEntry rosterEntry = null;
        try {
            rosterEntry = roster.getEntry(JidCreate.entityBareFrom(jabberId));
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (rosterEntry == null) {
            try {
                roster.createEntry(JidCreate.entityBareFrom(jabberId), name, null);
            } catch (SmackException.NotLoggedInException | SmackException.NotConnectedException | XMPPException.XMPPErrorException | SmackException.NoResponseException | InterruptedException | XmppStringprepException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendComposingState(String to, String thread, String state) {
        String chatIdentifier = (thread == null ? to : thread);

        ChatManager chatManager = ChatManager.getInstanceFor(connection);
        Chat chat = chatManager.getThreadChat(chatIdentifier);

        try {
            if (chat == null) {
                if (thread == null) {
                    chat = chatManager.createChat(JidCreate.entityBareFrom(to), chatMessageListener);
                } else {
                    chat = chatManager.createChat(JidCreate.entityBareFrom(to), thread, chatMessageListener);
                }
            }

            Message message = new Message();
            message.setFrom(connection.getUser());
            if (state.equalsIgnoreCase("composing")) {
                ChatStateExtension extension = new ChatStateExtension(ChatState.composing);
                message.addExtension(extension);
            } else {
                ChatStateExtension extension = new ChatStateExtension(ChatState.paused);
                message.addExtension(extension);
            }

            chat.sendMessage(message);

        } catch (SmackException | XmppStringprepException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 仅仅查询会议室成员名字
     */
    public void findMulitUser(String roomJid) {
        MultiUserChatManager mucManager = MultiUserChatManager.getInstanceFor(connection);

        try {
            MultiUserChat muc = mucManager.getMultiUserChat(JidCreate.entityBareFrom(roomJid));
            List<EntityFullJid> mucOccupants = muc.getOccupants();
            for (int i = 0; i < mucOccupants.size(); i++) {
                EntityFullJid entityFullJid = mucOccupants.get(i);
                if (entityFullJid != null) {
                    Resourcepart resourcepart = entityFullJid.getResourcepart();
                    Log.i(TAG, "findMulitUser: ----------------" + resourcepart.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "findMulitUser: e = " + e.getMessage());
        }
    }

    public void leaveRoom(String roomJid) {
        MultiUserChatManager mucManager = MultiUserChatManager.getInstanceFor(connection);

        try {
            MultiUserChat muc = mucManager.getMultiUserChat(JidCreate.entityBareFrom(roomJid));
            muc.leave();
            //删除在多用户聊天中收到任何新消息通知的节侦听器。
            // 只有针对此多用户聊天的“群聊”消息才会发送给收听者
            muc.removeMessageListener(messageListener);
        } catch (SmackException | InterruptedException | XmppStringprepException e) {
            e.printStackTrace();
            Log.e(TAG, "leaveRoom: e = " + e.getMessage());
        }
    }

    /**
     * 获得所有联系人
     */
    public Roster getContact() {
        Roster roster = Roster.getInstanceFor(connection);
        //获得所有的联系人组
        Collection<RosterGroup> groups = roster.getGroups();
        if (groups == null || groups.size() == 0) {
            Log.i(TAG, "getContact: 没有联系人");
            return null;
        }
        for (RosterGroup group : groups) {
            //获得每个组下面的好友
            List<RosterEntry> entries = group.getEntries();
            for (RosterEntry entry : entries) {
                //获得好友基本信息
                Log.i(TAG, "getContact: getUser == " + entry.getUser());
                Log.i(TAG, "getContact: getName == " + entry.getName());
                Log.i(TAG, "getContact: getType == " + entry.getType());
                Log.i(TAG, "getContact: getJid == " + entry.getJid());
                Log.i(TAG, "getContact: getGroups == " + entry.getGroups());
            }
        }
        return roster;
    }

    public void modifyRoomNickname(String roomJid, String roomNickname) {
        MultiUserChatManager mucManager = MultiUserChatManager.getInstanceFor(connection);

        try {
            Log.i(TAG, "modifyRoomNickname: roomJid = " + roomJid +
                    "   roomNickname = " + roomNickname);
            MultiUserChat muc = mucManager.getMultiUserChat(JidCreate.entityBareFrom(roomJid));
            //用户在群内昵称
            muc.changeNickname(Resourcepart.fromOrNull(roomNickname));
            //房间主题，需要【拥有者、管理员、成员及被排除者】中的（管理员）权限以上
            muc.changeSubject(roomNickname);
            if (!TextUtils.isEmpty(roomNickname)) {
                //房间配置，需要【拥有者、管理员、成员及被排除者】中的（拥有者）权限
                configRoom(muc, roomNickname);
                Log.i(TAG, "modifyRoomNickname-------1-------- ");
            } else {
                Log.i(TAG, "modifyRoomNickname-------2-------- ");
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "modifyRoomNickname: e = " + e.getMessage());
        }
    }


    @SuppressLint("NonConstantResourceId")
    public void onclick(View view) {
        switch (view.getId()) {
            case R.id.btn1:
                getConnection();
                break;
            case R.id.btn2:
                disconnect();
                break;
            case R.id.btn3:
                login(account, password);
                break;
            case R.id.btn4:
                logout();
                break;

            case R.id.btn5:
                joinRoom(roomJid, roomName, account, String.valueOf(new Date().getTime()));
                break;
            case R.id.btn6:
                leaveRoom(roomJid);
                break;
            case R.id.btn7:
                findMulitUser(roomJid);
                Roster contact = getContact();
                Log.i(TAG, "onclick: contact == " + contact);
                break;
            case R.id.btn8:
                sendRoomMessage(roomJid, "新消息=" + new Random().nextInt(1000));
                break;
            case R.id.btn9:
                sendRoomMessageUpdated(roomJid, "新消息=" + new Random().nextInt(1000), "swsQi-25");
                break;
            case R.id.btn10:
                modifyRoomNickname(roomJid, "xq" + new Random().nextInt(10000));
                break;
            case R.id.btn11:
                sendMessage("新好友消息=" + new Random().nextInt(1000), "xq233@192.168.0.134", null);
                break;
            case R.id.btn12:
                sendMessageUpdated("新好友消息=" + new Random().nextInt(1000), "xq233@192.168.0.134", null, "HXvaX-18");
                break;
            default:
                break;
        }
    }
}